package com.p2p.handler;

import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.p2p.constant.ErrorConstants;
import com.p2p.model.PeerMessage;
import com.p2p.service.AuthService;

/**
 * PeerJS信令服务器WebSocket处理器
 * 实现FRONTEND_INTERFACE.md中定义的通信协议
 * 处理客户端连接、消息转发和断开连接等逻辑
 */
@Component
public class PeerJsWebSocketHandler extends TextWebSocketHandler {

    private static final Logger logger = LoggerFactory.getLogger(PeerJsWebSocketHandler.class);

    private final AuthService authService;

    /**
     * 构造函数，使用构造函数注入AuthService
     * @param authService 认证服务
     */
    public PeerJsWebSocketHandler(AuthService authService) {
        this.authService = authService;
    }

    /**
     * 存储Peer ID与WebSocketSession的映射
     * 用于跟踪已连接的客户端，支持P2P消息的转发
     */
    private static final Map<String, WebSocketSession> PEER_SESSIONS = new ConcurrentHashMap<>();

    /**
     * 获取当前连接数
     * @return 当前连接数
     */
    public static int getPeerSessionsCount() {
        return PEER_SESSIONS.size();
    }
    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 连接建立时的处理
     * 对应文档中连接建立流程的第1步：客户端通过WebSocket连接到服务器
     * 在此方法中验证客户端提供的key和token参数
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        logger.info("Received WebSocket connection request from: {}", session.getRemoteAddress());
        // 获取查询参数
        Map<String, String> params = getQueryParams(session.getUri().getQuery());
        logger.info("WebSocket request parameters: {}", params);
        String key = params.get("key");
        String token = params.get("token");
        String peerId = params.get("id");

        // 处理JSON格式的id参数 (PeerJS客户端格式)
        if (peerId != null && peerId.startsWith("{")) {
            try {
                // 尝试解析JSON格式的id参数
                Map<String, String> idMap = objectMapper.readValue(peerId, Map.class);
                if (idMap.containsKey("id")) {
                    peerId = idMap.get("id");
                    logger.info("Parsed JSON id parameter: {}", peerId);
                }
            } catch (Exception e) {
                logger.warn("Failed to parse JSON id parameter: {}", e.getMessage());
            }
        }

        // 验证参数
        if (key == null || token == null) {
            logger.warn("WebSocket connection failed: Missing key or token parameters");
            // 参数缺失，发送错误消息并关闭连接
            try {
                PeerMessage errorMessage = PeerMessage.createErrorMessage(
                        ErrorConstants.INVALID_WS_PARAMETERS,
                        "Missing required parameters: key and token are required"
                );
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(errorMessage)));
                session.close(CloseStatus.BAD_DATA);
            } catch (Exception e) {
                logger.error("Failed to send error message: {}", e.getMessage());
                session.close(CloseStatus.SERVER_ERROR);
            }
            return;
        }

        // 验证key和token
        /*if (!authService.validateCredentials(key, token)) {
            logger.warn("WebSocket connection failed: Invalid API key or token");
            // 验证失败，发送错误消息并关闭连接
            PeerMessage errorMessage = PeerMessage.createErrorMessage(
                    ErrorConstants.INVALID_KEY_OR_TOKEN,
                    "Invalid API key or token"
            );
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(errorMessage)));
            session.close(new CloseStatus(401, "Unauthorized"));
            return;
        }*/

        // 验证Peer ID
        if (peerId == null || peerId.isEmpty()) {
            logger.warn("WebSocket connection failed: Missing peer ID");
            // Peer ID缺失，发送错误消息并关闭连接
            PeerMessage errorMessage = PeerMessage.createErrorMessage(
                    ErrorConstants.INVALID_WS_PARAMETERS,
                    "Missing required parameter: id"
            );
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(errorMessage)));
            session.close(CloseStatus.BAD_DATA);
            return;
        }

        // 检查Peer ID是否已被占用
        if (PEER_SESSIONS.containsKey(peerId)) {
            // ID已被占用，发送错误消息并关闭连接
            PeerMessage errorMessage = PeerMessage.createIdTakenMessage(peerId);
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(errorMessage)));
            session.close(new CloseStatus(409, "Conflict"));
            return;
        }

        // 检查最大连接数
        if (PEER_SESSIONS.size() >= getMaxConnections()) {
            // 达到最大连接数，发送错误消息并关闭连接
            PeerMessage errorMessage = PeerMessage.createErrorMessage(
                    ErrorConstants.SERVER_FULL,
                    "Server is full, maximum connections reached"
            );
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(errorMessage)));
            session.close(new CloseStatus(503, "Service Unavailable"));
            return;
        }

        // 所有验证通过，存储会话信息
        PEER_SESSIONS.put(peerId, session);
        session.getAttributes().put("peerId", peerId);
        logger.info("WebSocket connection established: {} with peerId: {}", session.getId(), peerId);
        System.out.println("WebSocket connection established: " + session.getId() + " with peerId: " + peerId);
    }

    /**
     * 解析查询参数
     * @param query 查询字符串
     * @return 参数映射
     */
    private Map<String, String> getQueryParams(String query) {
        Map<String, String> params = new ConcurrentHashMap<>();
        if (query != null) {
            String[] pairs = query.split("&");
            for (String pair : pairs) {
                String[] keyValue = pair.split("=", 2);
                if (keyValue.length == 2) {
                    params.put(keyValue[0], keyValue[1]);
                }
            }
        }
        return params;
    }

    @Value("${peerjs.max-connections}")
    private int maxConnections;

    /**
     * 获取最大连接数
     * @return 最大连接数
     */
    private int getMaxConnections() {
        return 100;
    }

    /**
     * 处理接收到的文本消息
     * 实现文档中消息类型与格式部分的处理逻辑
     * 包括OPEN、LEAVE、CANDIDATE、OFFER、ANSWER等消息类型
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 从属性中获取修复后的URI
        URI fixedUri = (URI) session.getAttributes().get("fixedUri");
        if (fixedUri != null) {
            // 使用修复后的URI进行后续处理
            System.out.println("处理来自URI的消息: " + fixedUri.toString());
        }
        // 处理接收到的消息
        String payload = message.getPayload();
        System.out.println("Received message: " + payload);

        try {
            // 解析消息
            PeerMessage peerMessage = objectMapper.readValue(payload, PeerMessage.class);
            String type = peerMessage.getType();
            String peerId = peerMessage.getPeerId();

            // 根据消息类型进行处理
            // 根据消息类型进行处理
            switch (type) {
                case "OPEN":
                    // 处理新连接，对应文档中连接建立流程的第2步和第3步
                    // 客户端发送OPEN消息，服务器验证并建立映射
                    PEER_SESSIONS.put(peerId, session);
                    // 存储Peer ID到Session属性中
                    session.getAttributes().put("peerId", peerId);
                    logger.info("Peer connected: {}", peerId);
                    System.out.println("Peer connected: " + peerId);
                    break;
                case "LEAVE":
                    // 处理离开消息，对应文档中断开连接流程的第1步
                    // 客户端发送LEAVE消息，服务器移除映射
                    PEER_SESSIONS.remove(peerId);
                    logger.info("Peer disconnected: {}", peerId);
                    System.out.println("Peer disconnected: " + peerId);
                    break;
                case "CANDIDATE":
                case "OFFER":
                case "ANSWER":
                    // 转发P2P信令消息，对应文档中建立P2P连接的流程
                    // OFFER: 步骤1，客户端A发送连接请求
                    // ANSWER: 步骤2，客户端B回应连接请求
                    // CANDIDATE: 步骤3，双方交换网络协商信息
                    String targetId = peerMessage.getTargetId();
                    WebSocketSession targetSession = PEER_SESSIONS.get(targetId);
                    if (targetSession != null && targetSession.isOpen()) {
                        targetSession.sendMessage(new TextMessage(payload));
                        logger.info("Forwarded {} message from {} to {}", type, peerId, targetId);
                        System.out.println("Forwarded " + type + " message from " + peerId + " to " + targetId);
                    } else {
                        logger.warn("Target peer not found or not connected: {}", targetId);
                        System.out.println("Target peer not found or not connected: " + targetId);
                    }
                    break;
                default:
                    logger.warn("Unknown message type: {}", type);
                    System.out.println("Unknown message type: " + type);
            }
        } catch (Exception e) {
            logger.error("Error processing message: {}", e.getMessage(), e);
            System.err.println("Error processing message: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 连接关闭时的处理
     * 对应文档中断开连接流程的第2步：服务器通知其他相关客户端
     * 和第3步：WebSocket连接关闭
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        // 连接关闭时的处理
        String peerId = (String) session.getAttributes().get("peerId");
        if (peerId != null) {
            PEER_SESSIONS.remove(peerId);
            logger.info("Peer disconnected: {}", peerId);
            System.out.println("Peer disconnected: " + peerId);
        }
        logger.info("WebSocket connection closed: {}", session.getId());
        System.out.println("WebSocket connection closed: " + session.getId());
    }

}
